// Scintilla source code edit control
/** @file CharClassify.cxx
 ** Character classifications used by Document and RESearch.
 **/
// Copyright 2006 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <cstdlib>
#include <cassert>
#include <cstring>

#include <vector>
#include <memory>

#include "CharacterSet.h"
#include "CharClassify.h"

using namespace Scintilla;

CharClassify::CharClassify() noexcept : charClass{} {
	SetDefaultCharClasses(true);
}

void CharClassify::SetDefaultCharClasses(bool includeWordClass) noexcept {
	// Initialize all char classes to default values
	for (int ch = 0; ch < 128; ch++) {
		if (IsEOLChar(ch))
			charClass[ch] = ccNewLine;
		else if (ch < 0x20 || ch == ' ')
			charClass[ch] = ccSpace;
		else if (includeWordClass && (IsAlphaNumeric(ch) || ch == '_'))
			charClass[ch] = ccWord;
		else
			charClass[ch] = ccPunctuation;
	}

	const int w = includeWordClass ? ccWord : ccPunctuation;
	memset(charClass + 128, w, 128);
}

void CharClassify::SetCharClasses(const unsigned char *chars, cc newCharClass) noexcept {
	// Apply the newCharClass to the specified chars
	if (chars) {
		const unsigned char w = static_cast<unsigned char>(newCharClass);
		while (*chars) {
			charClass[*chars] = w;
			chars++;
		}
	}
}

void CharClassify::SetCharClassesEx(const unsigned char *chars, int length) noexcept {
	if (chars == nullptr || length <= 0) {
		memset(charClass + 128, ccWord, 128);
	} else if (length == 16) {
		for (int i = 0; i < 128; i++) {
			const unsigned char w = 1 + ((chars[i >> 3] >> (i & 7)) & 1);
			charClass[i + 128] = w;
		}
	} else if (length == 32) {
		for (int i = 0; i < 128; i++) {
			const unsigned char w = (chars[i >> 2] >> (2 * (i & 3))) & 3;
			charClass[i + 128] = w;
		}
	}
}

int CharClassify::GetCharsOfClass(cc characterClass, unsigned char *buffer) const noexcept {
	// Get characters belonging to the given char class; return the number
	// of characters (if the buffer is NULL, don't write to it).
	int count = 0;
	for (int ch = maxChar - 1; ch >= 0; --ch) {
		if (charClass[ch] == characterClass) {
			++count;
			if (buffer) {
				*buffer = static_cast<unsigned char>(ch);
				buffer++;
			}
		}
	}
	return count;
}

namespace {

template <typename DataType, int DataSize, typename ValueType, int BufferSize, int ValueBit=3>
void ExpandRLE(const DataType (&data)[DataSize], ValueType (&buffer)[BufferSize]) noexcept {
	constexpr DataType mask = (1 << ValueBit) - 1;
	ValueType *p = buffer;

	for (int i = 0; i < DataSize; i++) {
		DataType ch = data[i];
		const ValueType value = ch & mask;
		ch >>= ValueBit;
		assert(p + ch <= buffer + BufferSize);
		while (ch--) {
			*p++ = value;
		}
	}
	// ensure full expanded
	assert(p == buffer + BufferSize);
}

//++Autogenerated -- start of section automatically generated
// Created with Python 3.8.2, Unicode 12.1.0
const unsigned short CharClassifyRLE_BMP[] = {
264, 123, 82, 59, 210, 51, 210, 35, 272, 75, 10, 19, 8, 35, 18, 11, 10, 27, 18, 11,
26, 11, 186, 11, 250, 11, 3666, 35, 98, 115, 42, 59, 10, 11, 10, 139, 938, 11, 18, 16,
34, 11, 10, 32, 19, 10, 11, 26, 8, 10, 8, 162, 8, 666, 11, 1114, 11, 1386, 8, 306,
16, 10, 51, 330, 19, 16, 27, 8, 362, 11, 10, 11, 18, 11, 18, 11, 10, 64, 218, 32,
34, 19, 136, 83, 90, 11, 16, 19, 594, 35, 818, 11, 66, 8, 11, 82, 11, 154, 19, 10,
115, 16, 474, 16, 810, 112, 434, 35, 10, 16, 10, 19, 370, 16, 123, 8, 226, 16, 11, 8,
90, 424, 170, 8, 66, 168, 122, 8, 1034, 19, 82, 11, 154, 8, 66, 16, 18, 16, 178, 8,
58, 8, 10, 24, 34, 16, 74, 16, 18, 16, 34, 64, 10, 32, 18, 8, 42, 16, 98, 19,
50, 19, 10, 11, 10, 16, 26, 8, 50, 32, 18, 16, 178, 8, 58, 8, 18, 8, 18, 8,
18, 16, 10, 8, 42, 32, 18, 16, 26, 24, 10, 56, 34, 8, 10, 56, 130, 11, 80, 26,
8, 74, 8, 26, 8, 178, 8, 58, 8, 18, 8, 42, 16, 82, 8, 26, 8, 26, 16, 10,
120, 34, 16, 82, 19, 56, 58, 8, 26, 8, 66, 16, 18, 16, 178, 8, 58, 8, 18, 8,
42, 16, 74, 16, 18, 16, 26, 64, 18, 32, 18, 8, 42, 16, 82, 11, 58, 80, 18, 8,
50, 24, 26, 8, 34, 24, 18, 8, 10, 8, 18, 24, 18, 24, 26, 24, 98, 32, 42, 24,
26, 8, 34, 16, 10, 48, 10, 112, 106, 67, 40, 106, 8, 26, 8, 186, 8, 130, 24, 66,
8, 26, 8, 34, 56, 18, 8, 26, 40, 34, 16, 82, 56, 11, 58, 11, 34, 11, 66, 8,
26, 8, 186, 8, 82, 8, 42, 16, 74, 8, 26, 8, 34, 56, 18, 56, 10, 8, 34, 16,
82, 8, 18, 104, 34, 8, 66, 8, 26, 8, 410, 8, 26, 8, 42, 11, 32, 130, 16, 154,
11, 50, 16, 18, 8, 146, 24, 194, 8, 74, 8, 10, 16, 58, 24, 10, 32, 50, 8, 10,
8, 66, 48, 82, 16, 18, 11, 96, 466, 32, 11, 122, 11, 82, 19, 296, 18, 8, 10, 8,
42, 8, 194, 8, 10, 8, 186, 16, 42, 8, 10, 8, 50, 16, 82, 16, 34, 256, 10, 187,
18, 51, 162, 11, 10, 11, 10, 11, 10, 35, 82, 8, 290, 32, 162, 11, 146, 8, 290, 8,
67, 10, 51, 8, 107, 296, 594, 51, 626, 19, 306, 8, 10, 40, 10, 16, 346, 11, 34, 2052,
586, 8, 34, 16, 58, 8, 10, 8, 34, 16, 330, 8, 34, 16, 266, 8, 34, 16, 58, 8,
10, 8, 34, 16, 122, 8, 458, 8, 34, 16, 538, 16, 26, 75, 162, 24, 130, 83, 48, 690,
16, 50, 16, 11, 4962, 19, 138, 8, 210, 19, 24, 602, 27, 90, 56, 106, 8, 58, 88, 170,
19, 72, 162, 96, 106, 8, 26, 8, 18, 96, 674, 27, 10, 35, 18, 16, 82, 48, 82, 48,
91, 26, 16, 82, 48, 714, 56, 346, 40, 562, 80, 250, 8, 98, 32, 98, 32, 11, 24, 19,
322, 16, 42, 88, 354, 32, 210, 48, 90, 24, 275, 226, 16, 19, 506, 8, 234, 16, 90, 48,
82, 48, 59, 10, 51, 16, 122, 520, 610, 32, 82, 139, 74, 75, 24, 930, 64, 35, 450, 24,
43, 82, 24, 394, 19, 74, 56, 346, 16, 26, 67, 64, 26, 11, 314, 40, 2002, 8, 2266, 16,
50, 16, 306, 16, 50, 16, 66, 8, 10, 8, 10, 8, 10, 8, 250, 16, 426, 8, 58, 11,
10, 27, 26, 8, 58, 27, 34, 16, 50, 8, 27, 106, 27, 16, 26, 8, 58, 19, 136, 195,
17, 48, 379, 136, 18, 16, 50, 43, 90, 43, 8, 106, 24, 259, 128, 266, 120, 19, 10, 35,
10, 19, 82, 11, 10, 27, 42, 51, 10, 11, 10, 11, 10, 11, 34, 11, 90, 19, 34, 43,
42, 35, 10, 11, 466, 19, 32, 5307, 200, 91, 168, 482, 627, 178, 5043, 242, 7939, 16, 259, 16,
835, 378, 8, 378, 8, 1066, 51, 74, 40, 35, 10, 19, 306, 8, 10, 40, 10, 16, 450, 56,
10, 11, 112, 194, 72, 58, 8, 58, 8, 58, 8, 58, 8, 58, 8, 58, 8, 58, 8, 58,
8, 258, 379, 10, 259, 384, 211, 8, 715, 96, 1715, 208, 99, 40, 35, 28, 203, 124, 11, 44,
19, 44, 27, 8, 692, 16, 20, 19, 28, 11, 724, 11, 36, 40, 348, 8, 756, 8, 19, 36,
83, 220, 40, 291, 96, 132, 251, 8, 84, 243, 68, 11, 124, 259, 84, 315, 124, 2563, 52660, 80,
515, 65532, 65532, 36756, 128, 9324, 24, 443, 72, 370, 19, 2154, 27, 226, 160, 410, 11, 82, 11, 922,
51, 64, 187, 74, 19, 826, 19, 426, 16, 42, 384, 394, 35, 32, 50, 35, 48, 418, 35, 64,
562, 64, 19, 82, 48, 194, 27, 10, 11, 394, 19, 290, 88, 11, 236, 24, 522, 107, 8, 90,
32, 19, 250, 8, 442, 72, 114, 16, 82, 16, 35, 186, 27, 586, 192, 26, 19, 130, 19, 42,
80, 50, 16, 50, 16, 50, 72, 58, 8, 58, 8, 346, 11, 98, 64, 986, 11, 18, 16, 82,
48, 65532, 23852, 96, 188, 32, 396, 65528, 2088, 2932, 16, 852, 304, 58, 96, 42, 40, 98, 11, 106,
8, 42, 8, 10, 8, 18, 8, 18, 8, 866, 131, 136, 2906, 19, 128, 514, 16, 434, 320, 98,
19, 16, 130, 83, 48, 130, 283, 8, 155, 8, 35, 32, 42, 8, 1082, 32, 123, 82, 59, 210,
51, 210, 91, 716, 24, 52, 16, 52, 16, 52, 16, 28, 24, 59, 8, 59, 104, 19, 16,
};

}

const unsigned char CharClassify::CharClassifyTable[] = {
// CharClassifyTable1
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 40, 44, 48, 40, 40, 40, 52, 40, 40,
40, 40, 40, 40, 40, 40, 56, 60, 64, 64, 64, 64, 64, 68, 72, 40, 40, 40, 40, 40,
40, 40, 40, 40, 76, 40, 40, 80, 40, 40, 40, 40, 84, 88, 92, 40, 96, 40, 100, 104,
108, 112, 116, 40, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 120, 64, 64, 64, 124, 128, 64, 64, 64, 64, 132, 64, 64, 64, 64,
64, 64, 136, 40, 40, 40, 140, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 144, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40,
// CharClassifyTable2
0, 1, 2, 3, 4, 4, 5, 5, 1, 1, 1, 1, 1, 1, 1, 6, 7, 1, 1, 8,
1, 1, 1, 9, 10, 11, 12, 5, 5, 13, 13, 14, 5, 5, 5, 5, 5, 5, 5, 5,
1, 15, 1, 1, 1, 16, 1, 17, 1, 1, 18, 1, 6, 1, 1, 6, 1, 19, 1, 1,
20, 21, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 22, 1, 1, 20, 1, 17,
1, 1, 23, 1, 1, 1, 24, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 25, 1, 26, 23, 5,
5, 5, 5, 5, 5, 5, 5, 5, 27, 1, 1, 28, 1, 29, 1, 30, 1, 31, 32, 5,
5, 5, 1, 33, 1, 34, 1, 35, 5, 5, 5, 5, 1, 1, 1, 36, 1, 37, 1, 1,
38, 39, 1, 40, 41, 42, 1, 43, 1, 1, 5, 5, 44, 1, 45, 46, 1, 1, 1, 47,
1, 48, 1, 49, 1, 50, 51, 5, 5, 5, 5, 5, 1, 1, 1, 1, 41, 5, 5, 5,
1, 1, 1, 52, 1, 1, 1, 53, 1, 1, 23, 22, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 31, 5, 5, 5, 5, 5, 5, 5, 5,
1, 1, 23, 1, 1, 54, 5, 5, 5, 5, 5, 5, 5, 5, 1, 25, 1, 1, 1, 1,
55, 37, 1, 56, 1, 1, 1, 57, 58, 1, 41, 22, 1, 1, 1, 59, 60, 1, 1, 61,
1, 1, 1, 1, 62, 63, 64, 65, 1, 66, 1, 67, 5, 5, 5, 5, 68, 69, 70, 1,
1, 1, 6, 22, 71, 72, 73, 74, 75, 76, 77, 65, 5, 5, 5, 5, 5, 5, 5, 5,
1, 1, 1, 1, 78, 79, 5, 5, 1, 1, 1, 1, 80, 22, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 1, 1, 1, 48, 81, 82, 5, 5, 1, 1, 1, 1, 83, 22, 84, 5,
1, 1, 1, 41, 22, 5, 5, 5, 1, 85, 17, 86, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 1, 1, 1, 87, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 88,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 89, 1, 1, 89, 90, 5, 1, 1, 1, 43,
91, 1, 1, 1, 1, 92, 93, 5, 1, 1, 1, 41, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 73, 1, 1, 2, 94, 1, 15, 95, 1, 37, 96, 25,
5, 5, 5, 5, 97, 1, 1, 98, 23, 22, 99, 1, 31, 100, 22, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 101, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 1, 102, 13, 103, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1,
1, 1, 31, 104, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 105, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 31, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 25, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 41, 1, 31, 106, 5, 5, 5, 5, 5,
5, 1, 4, 107, 1, 1, 1, 108, 109, 110, 66, 111, 1, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1,
1, 112, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 113, 1, 1, 1, 114, 1, 5, 5,
5, 5, 115, 5, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 117, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 118,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 119, 5, 5, 5, 118, 120, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 121, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
1, 1, 1, 1, 1, 1, 6, 15, 41, 122, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 123,
13, 13, 124, 13, 13, 13, 125, 126, 127, 13, 128, 13, 13, 13, 42, 5, 13, 13, 13, 13,
129, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 105, 13, 13, 13, 13, 13, 46, 1, 41,
5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 59, 1, 1, 1, 130, 131, 132,
133, 1, 1, 1, 134, 135, 1, 136, 137, 138, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 48, 1, 139, 140, 1, 140, 1, 141, 1, 141,
43, 1, 43, 1, 142, 1, 142, 1, 143, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 1, 1, 1, 144, 1, 1, 145, 146, 147, 148, 64, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 149, 150, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 15, 4, 151, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
1, 1, 1, 35, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 152, 25, 5, 5, 1, 1, 1, 1,
17, 106, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 64, 1, 1, 153, 154, 5, 5, 5, 5,
64, 1, 155, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 133, 1, 156, 157,
158, 159, 160, 161, 110, 17, 162, 17, 5, 5, 5, 58, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 13, 13, 11, 13, 13, 13, 13, 13, 13, 163, 164, 165,
165, 165, 13, 123, 15, 13, 13, 13, 13, 13, 84, 13, 13, 13, 84, 5, 5, 5, 166, 13,
93, 13, 13, 11, 42, 58, 123, 5, 5, 5, 5, 5, 5, 5, 5, 5, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 123, 84, 167,
13, 13, 13, 13, 13, 13, 13, 163, 13, 13, 13, 13, 13, 42, 11, 5, 11, 13, 13, 13,
168, 169, 13, 13, 168, 13, 170, 5, 5, 5, 5, 5, 171, 13, 13, 13, 13, 13, 13, 172,
13, 13, 173, 13, 174, 13, 13, 13, 13, 13, 13, 13, 13, 163, 170, 175, 93, 123, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 176, 5, 5, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 177, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 178, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 179, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 180, 5,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 178, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5,
// CharClassifyTable
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,
2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 3, 3, 3, 3, 3,
3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 0, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 3,
2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2,
2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0,
0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0,
2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 0, 0, 0,
2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 3, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 0, 0, 0, 0, 0, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 3, 2, 2, 2, 2,
2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 0, 0, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3,
3, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 3, 3, 3, 3,
3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0,
0, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 3, 3, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
3, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 3, 3, 3,
3, 2, 2, 2, 2, 3, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
2, 3, 3, 3, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 2,
2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2,
2, 2, 2, 2, 2, 0, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 2, 0, 0, 2, 0, 0, 0,
0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2,
2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 3, 0, 3, 2, 2,
2, 2, 2, 2, 2, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 0, 0, 2, 3, 3, 3, 2, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 3, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2,
2, 2, 3, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3,
3, 3, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 3, 3, 3, 2, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 2, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,
2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 0,
2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 0, 2, 2, 2, 2, 2, 2,
2, 2, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
2, 2, 2, 3, 3, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 3, 3, 2, 2, 2, 2, 2, 3, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
3, 3, 3, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,
0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2,
4, 4, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0,
0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 0, 0, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 0,
0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2,
2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2,
2, 2, 3, 3, 3, 3, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 0, 0, 2, 0,
0, 2, 2, 0, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 0, 2, 2, 2,
2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 0,
0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2,
2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2,
0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3,
3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2,
2, 2, 0, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 2, 3, 2, 2, 2, 2, 2, 0, 0, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 2, 2, 2, 3, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 0, 2, 2, 0,
2, 0, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2,
0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 2, 0, 2,
0, 2, 2, 2, 0, 2, 2, 0, 2, 0, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2,
0, 2, 2, 0, 2, 0, 0, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0,
2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 2, 0, 0, 2, 2, 2, 0, 2, 2, 2,
2, 2, 0, 2, 2, 2, 2, 2, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0,
0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0,
0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0,
0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0,
0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 0,
0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 3,
3, 3, 3, 3, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 4, 4, 4, 4,
4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
//--Autogenerated -- end of section automatically generated

unsigned char CharClassify::classifyMap[0xffff + 1];

void CharClassify::InitUnicodeData() noexcept {
	ExpandRLE(CharClassifyRLE_BMP, classifyMap);
#ifndef NDEBUG // Debug test only
	DBCSCharClassify::Get(932);
	DBCSCharClassify::Get(936);
	DBCSCharClassify::Get(949);
	DBCSCharClassify::Get(950);
	DBCSCharClassify::Get(1361);
#endif
}

namespace {

inline void SetRange(bool bs[256], int low, int high) noexcept {
	while (low <= high) {
		bs[low] = true;
		++low;
	}
}

std::vector<std::unique_ptr<DBCSCharClassify>> dbcsCharClassifyList;

//dbcs++Autogenerated -- start of section automatically generated
// Created with Python 3.8.0, Unicode 12.1.0
const unsigned short CharClassifyRLE_CP932[] = {
264, 123, 82, 59, 210, 51, 210, 35, 264, 12, 43, 468, 232, 28, 65528, 65528, 65528, 65528, 552, 139,
36, 11, 44, 283, 8, 395, 60, 451, 10, 99, 536, 123, 82, 59, 210, 11, 18, 11, 10, 8,
11, 210, 35, 692, 600, 508, 8, 188, 64, 194, 67, 282, 83, 84, 8, 52, 536, 266, 123, 122,
8, 146, 36, 19, 26, 291, 244, 64, 67, 114, 552, 11, 8, 35, 10, 11, 8, 19, 18, 19,
18, 11, 26, 11, 330, 8, 258, 11, 82, 11, 66, 11, 266, 11, 306, 536, 282, 8, 26, 64,
66, 11, 58, 8, 43, 16, 82, 11, 362, 411, 72, 19, 536, 250, 187, 10, 56, 11, 8, 251,
756, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8,
1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8,
1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8,
1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8,
1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 65528, 65528, 552,
508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536,
508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536,
508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536,
508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536,
508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536,
508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 1004, 536, 508, 8, 940, 6232,
};

const unsigned short CharClassifyRLE_CP936[] = {
264, 123, 82, 59, 210, 51, 210, 35, 65528, 65528, 65528, 65528, 1576, 508, 8, 1020, 520, 508, 8, 1020,
520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020,
520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020,
520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020,
520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020,
520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020,
520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020,
520, 508, 8, 268, 8, 27, 18, 19, 12, 683, 520, 508, 8, 268, 82, 48, 402, 16, 84, 16,
98, 536, 508, 8, 268, 123, 82, 59, 210, 51, 210, 35, 520, 508, 8, 932, 608, 508, 8, 956,
584, 508, 8, 268, 194, 64, 194, 56, 99, 16, 43, 8, 19, 592, 508, 8, 268, 266, 120, 266,
624, 18, 491, 8, 179, 88, 218, 8, 18, 8, 10, 32, 300, 688, 76, 123, 8, 19, 8, 11,
24, 12, 19, 44, 187, 8, 75, 104, 12, 104, 611, 640, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 980, 560, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520, 508, 8, 1020, 520,
508, 8, 1020, 520, 508, 8, 1020, 520, 132, 648, 756, 2056,
};

const unsigned short CharClassifyRLE_CP949[] = {
264, 123, 82, 59, 210, 51, 210, 35, 65528, 65528, 65528, 65528, 1584, 212, 48, 212, 48, 1012, 528, 212,
48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212,
48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012,
528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212,
48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212,
48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012,
528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212,
48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212,
48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012,
528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212,
48, 212, 48, 1012, 528, 212, 48, 212, 48, 260, 8, 59, 8, 259, 10, 419, 528, 212, 48, 212,
48, 260, 51, 10, 67, 10, 443, 712, 212, 48, 212, 48, 260, 123, 82, 59, 210, 51, 210, 35,
528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 260, 82, 40, 82, 56, 194, 64, 194, 576,
212, 48, 212, 48, 260, 547, 736, 212, 48, 212, 48, 260, 27, 10, 419, 10, 179, 648, 212, 48,
212, 48, 260, 34, 8, 10, 8, 66, 8, 435, 194, 528, 212, 48, 212, 48, 260, 130, 435, 194,
528, 212, 48, 212, 48, 924, 616, 212, 48, 212, 48, 948, 592, 212, 48, 212, 48, 260, 266, 120,
266, 632, 212, 48, 212, 48, 260, 1280, 212, 48, 212, 48, 260, 1280, 212, 48, 212, 48, 260, 1280,
212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48,
212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48,
1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528,
212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48,
212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48,
1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528,
212, 48, 212, 48, 1012, 528, 212, 48, 212, 48, 1012, 528, 148, 624, 756, 1296, 756, 1296, 756, 3344,
756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296,
756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296,
756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296,
756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296,
756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296, 756, 1296,
756, 1296, 756, 4104,
};

const unsigned short CharClassifyRLE_CP950[] = {
264, 123, 82, 59, 210, 51, 210, 35, 8, 65532, 65532, 65532, 65532, 65532, 1580, 8, 499, 276, 291, 10,
459, 524, 203, 76, 235, 276, 115, 162, 100, 386, 524, 418, 572, 11, 34, 65532, 8612, 82, 65532, 49188,
};

const unsigned short CharClassifyRLE_CP1361[] = {
264, 123, 82, 59, 210, 51, 210, 35, 65528, 65528, 65528, 65528, 7736, 132, 8, 92, 24, 12, 248, 12,
248, 12, 248, 12, 248, 12, 760, 12, 248, 12, 248, 12, 248, 12, 248, 12, 248, 12, 760, 12,
248, 12, 248, 12, 248, 12, 248, 12, 248, 12, 760, 12, 248, 12, 248, 12, 248, 12, 1272, 12,
248, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 1048, 12, 248, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 1048, 12, 248, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 1048, 12, 248, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 1048, 12, 248, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 1048, 12, 248, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 1048, 12, 248, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
1048, 12, 248, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 1048, 12, 248, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 1048, 12, 248, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 1048, 12,
248, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 1048, 12, 248, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 1048, 12, 248, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 1048, 12, 248, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 1048, 12, 248, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 1048, 12, 248, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 1048, 12, 248, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
1048, 12, 248, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140,
8, 92, 24, 140, 8, 92, 1048, 12, 248, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92, 24, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 536, 140, 8, 92,
24, 140, 8, 92, 24, 140, 8, 92, 24, 140, 8, 92, 11168, 59, 8, 259, 10, 291, 144, 179,
10, 67, 10, 443, 584, 123, 82, 59, 210, 51, 114, 144, 98, 35, 408, 348, 400, 82, 40, 82,
56, 194, 64, 114, 144, 82, 48, 547, 608, 27, 10, 419, 10, 171, 144, 11, 120, 34, 8, 10,
8, 66, 8, 435, 194, 400, 130, 435, 66, 144, 130, 668, 488, 628, 144, 68, 64, 266, 120, 266,
2552, 628, 144, 884, 400, 628, 144, 884, 400, 628, 144, 884, 400, 628, 144, 884, 400, 628, 144, 884,
400, 628, 144, 884, 400, 628, 144, 884, 400, 628, 144, 884, 400, 628, 144, 884, 400, 628, 144, 884,
400, 628, 144, 884, 400, 628, 144, 884, 400, 628, 144, 884, 400, 628, 144, 884, 400, 628, 144, 884,
400, 628, 144, 884, 400, 628, 144, 884, 400, 628, 144, 884, 400, 628, 144, 884, 400, 628, 144, 884,
400, 628, 144, 884, 400, 628, 144, 884, 400, 628, 144, 884, 400, 628, 144, 884, 400, 628, 144, 884,
400, 628, 144, 884, 12296,
};
//dbcs--Autogenerated -- end of section automatically generated
}

DBCSCharClassify::DBCSCharClassify(int codePage_) noexcept:
	codePage(codePage_),
	leadByte{},
	invalidLeadByte{},
	invalidTrailByte{} {
	// Byte ranges found in Wikipedia articles with relevant search strings in each case
	switch (codePage_) {
	case 932:
		// Shift_JIS
		SetRange(leadByte, 0x81, 0x9F);
		SetRange(leadByte, 0xE0, 0xFC);
		// Lead bytes F0 to FC may be a Microsoft addition.

		invalidLeadByte[0x85] = true;
		invalidLeadByte[0x86] = true;
		invalidLeadByte[0xEB] = true;
		invalidLeadByte[0xEC] = true;
		invalidLeadByte[0xEF] = true;
		invalidLeadByte[0xFA] = true;
		invalidLeadByte[0xFB] = true;
		invalidLeadByte[0xFC] = true;

		SetRange(invalidTrailByte, 0x00, 0x3F);
		invalidTrailByte[0x7F] = true;
		SetRange(invalidTrailByte, 0xFD, 0xFF);

		ExpandRLE(CharClassifyRLE_CP932, classifyMap);
		break;

	case 936:
		// GBK
		SetRange(leadByte, 0x81, 0xFE);

		invalidLeadByte[0x80] = true;
		invalidLeadByte[0xFF] = true;

		SetRange(invalidTrailByte, 0x00, 0x3F);
		invalidTrailByte[0x7F] = true;
		invalidTrailByte[0xFF] = true;

		ExpandRLE(CharClassifyRLE_CP936, classifyMap);
		break;

	case 949:
		// Korean Unified Hangul Code, Wansung KS C-5601-1987
		SetRange(leadByte, 0x81, 0xFE);

		invalidLeadByte[0x80] = true;
		invalidLeadByte[0xC9] = true;
		invalidLeadByte[0xFE] = true;
		invalidLeadByte[0xFF] = true;

		SetRange(invalidTrailByte, 0x00, 0x40);
		SetRange(invalidTrailByte, 0x5B, 0x60);
		SetRange(invalidTrailByte, 0x7B, 0x80);
		invalidTrailByte[0xFF] = true;

		ExpandRLE(CharClassifyRLE_CP949, classifyMap);
		break;

	case 950:
		// Big5
		SetRange(leadByte, 0x81, 0xFE);

		SetRange(invalidLeadByte, 0x80, 0xA0);
		invalidLeadByte[0xC8] = true;
		SetRange(invalidLeadByte, 0xFA, 0xFF);

		SetRange(invalidTrailByte, 0x00, 0x3F);
		SetRange(invalidTrailByte, 0x7F, 0xA0);
		invalidTrailByte[0xFF] = true;

		ExpandRLE(CharClassifyRLE_CP950, classifyMap);
		break;

	case 1361:
		// Korean Johab, KS C-5601-1992
		SetRange(leadByte, 0x84, 0xD3);
		SetRange(leadByte, 0xD8, 0xDE);
		SetRange(leadByte, 0xE0, 0xF9);

		SetRange(invalidLeadByte, 0x80, 0x83);
		SetRange(invalidLeadByte, 0xD4, 0xD8);
		invalidLeadByte[0xDF] = true;
		SetRange(invalidLeadByte, 0xFA, 0xFF);

		SetRange(invalidTrailByte, 0x00, 0x30);
		invalidTrailByte[0x80] = true;
		invalidTrailByte[0xFF] = true;

		ExpandRLE(CharClassifyRLE_CP1361, classifyMap);
		break;
	}
}

const DBCSCharClassify* DBCSCharClassify::Get(int codePage) {
	if (IsDBCSCodePage(codePage)) {
		for (const auto &dbcs : dbcsCharClassifyList) {
			if (dbcs->codePage == codePage) {
				return dbcs.get();
			}
		}

		dbcsCharClassifyList.push_back(std::unique_ptr<DBCSCharClassify>(new DBCSCharClassify(codePage)));
		return dbcsCharClassifyList.back().get();
	}
	return nullptr;
}
